﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TanmiaGrp.Basis.Core;
using TanmiaGrp.GeneralLedger.Core;

namespace TanmiaGrp.GeneralLedger.SqlServerRepository
{
    internal class GlDbContext : DbContext
    {
        public static readonly string IX_AccountName = "IX_Account_AccountName";
        public static readonly string IX_AccountNumber = "IX_Account_AccountNumber";

        [ThreadStatic]
        private static DbContext current;
        public static DbContext Current
        {
            get
            {
                if (current == null)
                    current = new GlDbContext();

                return current;
            }
        }

        public static void Clean()
        {
            if (current != null)
                current.Dispose();

            current = null;
        }

        public DbSet<Core.Group> Groups { get; set; }
        public DbSet<Core.Account> Accounts { get; set; }
        public DbSet<Core.Journal> Journals { get; set; }

        public GlDbContext()
            : base("CnnStr")
        {
            this.Configuration.LazyLoadingEnabled = true;
            //((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += ObjectContext_ObjectMaterialized;
        }

        #region Helper Methods

        private void ObjectContext_ObjectMaterialized(object sender, System.Data.Entity.Core.Objects.ObjectMaterializedEventArgs e)
        {
            foreach (PropertyInfo prop in e.Entity.GetType().GetProperties().Where(x => x.GetIndexParameters().Count() == 0))
            {
                DbCollectionEntry collectionEntry = Entry(e.Entity).Member(prop.Name) as DbCollectionEntry;
                if (collectionEntry != null)
                {
                    Type elementType = TryGetElementType(prop);
                    if (elementType != null)
                    {
                        Type lazyCollectionType = typeof(LazyObservableCollection<>).MakeGenericType(elementType);
                        collectionEntry.CurrentValue = Activator.CreateInstance(lazyCollectionType, collectionEntry.CurrentValue, collectionEntry);
                    }
                }
            }
        }

        private Type TryGetElementType(PropertyInfo collectionProperty)
        {
            // We can only replace properties that are declared as ICollection<T>
            // and have a setter.
            var propertyType = collectionProperty.PropertyType;
            if (propertyType.IsGenericType &&
                propertyType.GetGenericTypeDefinition() == typeof(ICollection<>) &&
                collectionProperty.GetSetMethod() != null)
            {
                return propertyType.GetGenericArguments().Single();
            }
            return null;
        }

        #endregion

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

            modelBuilder.Entity<Account>()
                .Property(x => x.AccountName)
                .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute(IX_AccountName) { IsUnique = true }));

            modelBuilder.Entity<Account>()
                .Property(x => x.AccountNumber)
                .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute(IX_AccountNumber) { IsUnique = true }));

            modelBuilder.Entity<Account>()
                .HasMany<Group>(np => np.AccountGroups)
                .WithMany()
                .Map(x =>
                {
                    x.MapLeftKey("AccountID");
                    x.MapRightKey("GroupID");
                    x.ToTable("AccountGroup");
                });

            modelBuilder.Entity<Account>()
                .HasOptional<Account>(np => np.Parent)
                .WithMany(np => np.AccountChildren)
                .HasForeignKey(fk => fk.ParentAccountID);

            modelBuilder.Entity<Account>()
                .HasOptional<Account>(np => np.FinalAccount)
                .WithMany()
                .HasForeignKey(fk => fk.FinalAccountID);

            base.OnModelCreating(modelBuilder);
        }

        //public void AttachGraph<T>(T entity)
        //    where T : BusinessObject
        //{
        //    Set<T>().Add(entity);

        //    if (entity.p
        //}
    }
}
